home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 52
/
Aminet 52 (2002)(GTI - Schatztruhe)[!][Dec 2002].iso
/
Aminet
/
misc
/
emu
/
Apex-src.lha
/
ED.XPL
< prev
next >
Wrap
Text File
|
2001-09-30
|
46KB
|
1,747 lines
\ED.XPL MAY-17-90 (Version 1.1; see HELP and INITIALIZE)
\By Richard Ottosen and Loren Blaney
\This is a version of VED/MRED written in XPL to run on the 68000.
\
\REVISION HISTORY:
\ NOV-84, Original version, R.O.
\ FEB-86, Modified for DFM Engineering, L.B.
\ AUG-86, Fixed some bugs and added some enhancements, L.B.
\ NOV-29-86, Added fast disk I/O, BLIT backwards, and fixed sliding cursor.
\ DEC-04-86, Fixed restart to allow concatenating files, cleaned HELP menus.
\ DEC-12-86, Fixed Close and N buffer search, L.B.
\ MAR-11-87, Modified for the Amiga, L.B.
\ APR-11-87, Changed string and BLIT conventions.
\ JUL-06-88, Speed up screen display slightly, add mods for 24/48 line toggle.
\ MAY-17-90, Fix margin command for last paragraph when not terminated by a CR.
\
\NOTES:
\See HELP for the directions.
\
\Terminal-specific code is marked "%%%".
\
\This text editor is always in insert mode. Characters may be rapidly inserted
\ because the text in the edit buffer is split at the point where the cursor
\ is. Inserted characters are simply stored in the split -- the rest of the
\ text does not need to be moved.
\
\If the screen looks like this:
\
\ The quick brown fox jumps over the lazy dog.
\ ^
\ Displayed cursor
\
\The edit buffer will look like this:
\
\ The quick brown fox jum................................ps over the lazy dog.
\ ^ ^
\ CINX C2INX
\
\If an "X" is inserted, the screen will look like this:
\
\ The quick brown fox jumXps over the lazy dog.
\ ^
\ Displayed cursor
\
\ and the edit buffer will look like this:
\
\ The quick brown fox jumX...............................ps over the lazy dog.
\ ^ ^
\ CINX C2INX
\
\When CINX = C2INX, the edit buffer is full and no more characters may be
\ inserted.
code
ABS=0, RAN=1, REM=2, RESERVE=3,
SWAP=4, EXTEND=5, RESTART=6, CHIN=7,
CHOUT=8, CRLF=9, INTIN=10, INTOUT=11,
TEXT=12, OPENI=13, OPENO=14, CLOSE=15,
ABORT=16, \TRAP=17,\ FREE=18, \GETERR=22,\
CURSOR=23, BLIT=36,
BUTES=124, GETKEY=125, KEYHIT=126, SHOCUR=127;
ext CHIN3=$C00, CHOUT3=$C06;
def CHKUSRF= $69C; \flag to enable CTRL-C = abort, etc.
def PR=2, DISK=3;
def CTRLA= $01, CTRLB= $02, CTRLC= $03, CTRLD= $04,
CTRLE= $05, CTRLF= $06, CTRLG= $07, CTRLH= $08,
CTRLI= $09, CTRLJ= $0A, CTRLK= $0B, CTRLL= $0C,
CTRLM= $0D, CTRLN= $0E, CTRLO= $0F, CTRLP= $10,
CTRLQ= $11, CTRLR= $12, CTRLS= $13, CTRLT= $14,
CTRLU= $15, CTRLV= $16, CTRLW= $17, CTRLX= $18,
CTRLY= $19, CTRLZ= $1A,
BEL= $07, TAB= $09, LF= $0A, FF= $0C,
CR= $0D, EOF= $1A, ESC= $1B, DEL= $7F,
SP= $20, \space char
SPIND= ^_, \indicator for a space when showing control chars
WILDCH= CTRLW; \wild character matches anything in a search
def XBUFSIZ= 5000, \scoop (X register) buffer size
PAD= XBUFSIZ, \space left when reading in a file
COLMAX= 255, \maximum possible column (with horz scrolling)
DBUFSIZ= 256; \size of deferred command (line) buffer
\WARNING: status display assumes 80 columns and
\ HELP menus assume 24 lines
def CONWIDE= $69E, CONHIGH= $69F; \SYSPAG parameters (screen size)
int CINX, \char position index (in text buffer)
C2INX, \second char position index
SCINX, \saved char pointers for OOPS command
SC2INX,
ACINX, \auxillary cursor
DINX, \array: index for command line buffer (points to end +1)
XINX, \index for X register (scoop)
CHAR, \holds character struck on keyboard
CURH, \horizontal posn of cursor from last CR. This is COL:
\ on the status line, (0 through COLMAX).
CURL, \line on the screen where the cursor is currently
CURLINE, \screen line where the edit-buffer cursor appears
LEFTCOL, \column number of the left-most displayed char
\ (= number of chars scrolled off of left edge)
RIGHTCOL, \column number + 1 of the right-most displayed char
BUFSIZ, \size of edit buffer (bytes)
XFLAG, \scoop (X reg) is enabled
EOFFLAG, \EOF is read from input file
CLOSFLAG, \output file has been closed
ERRFLAG, \error flag used for terminating command-line loop
DBUF, \array of buffers: deferred command (line) buffer
DN, \current DBUF [0-9]
REMAIN, \remaining char space
II, \scratch for MAIN
WIDTH, \number of chars per line
HEIGHT; \number of lines on the screen
reg addr BUFFER; \main text buffer
addr XBUF, \scoop buffer (X register)
STATCOND, \status condition message string (8 chars max)
TICKMARKS, \ruler tick marks
SSTR, \search string, must be global because of XPL bug
ADDR; \used to access absolute addresses
int PARAMS; \initialization parameters (may be saved with program)
def \PARAMS\ \note: order must agree with constant array
COLDFLAG, \true if not a restart
LEFTMARGIN, \left margin column position
RIGHTMARGIN, \right margin column position (last char is in this col)
BELLCOL, \column for end-of-line bell
PARAINDENT, \number of spaces to indent the beginning of paragraphs
S1FLAG, \ignore upper/lower case in searches
S2FLAG, \search backwards
SHOWFLAG; \show the control chars
\----------------------------------------------------------------------
func KEYIN; \Get a character from the keyboard
\Inputs: CURH, LEFTCOL.
int CHAR, H;
begin
H:= CURH -LEFTCOL; \get the screen's position, [0-79]
if H<0 then H:= 0;
if H > WIDTH-1 then H:= WIDTH-1;
CURSOR(H, CURL);
SHOCUR(true);
repeat until KEYHIT; \wait for a character
CHAR:= GETKEY;
if CHAR>=$20 & CHAR<=$7E then \echo printable characters immediately
[CHOUT(0,CHAR);
CURH:= CURH +1]; \anticipate the cursor position for fast typing
SHOCUR(false);
WIDTH:= ADDR(CONWIDE); \set HEIGHT & WIDTH in case they changed
HEIGHT:= ADDR(CONHIGH);
CURLINE:= (HEIGHT -6); \put cursor on 3rd line from bottom
\ (in case HEIGHT changed)
return CHAR;
end; \KEYIN
\----------------------------------------------------------------------
proc HELP(DEV); \Show/print HELP screen
\(DON'T straighten up the text until you see what "^" does.)
int DEV;
begin
if DEV=0 ! DEV=1 then CHOUT(0,FF) else OPENO(DEV);
TEXT(DEV,"ED, V1.1 -- IMMEDIATE COMMANDS --
MOVE ADDITIONAL CHARACTERS
^^A - Ahead a character ^^I - Tab
^^Q - Back a character --> - Indent Under line above (^^U)
^^N - Ahead to Next word ^^L - Form feed (new page)
^^B - Back a word ^^Z - Shift case and move ahead
^^S - Ahead a line ^^T - Display control chars (on/off)
^^W - Back a line ^^^^ - Always insert next keystroke
^^J - Ahead a page (down arrow)
^^K - Back a page (up arrow) SCOOP
^^D - Ahead to end of text buffer ^^R - Start (or Resume) a scoop-up
^^E - Back to start of text buffer ^^F - Finish a scoop-up
^^Y - Insert scoop and erase it
DELETE COMMAND LINE
<-- - Back a character (^^H) ESC - Enter command-line mode
^^C - Back a word ^^G - Re-execute command line (Go)
^^X - Back a line ^^V - Copy command line into text
^^O - Undelete (Oops!) ^^P - Select command line (0-9)
^^] - Change search case sensitivity
^^_ - Reverse search direction
(^^ = CTRL key)");
if DEV = 0 then
begin
CURSOR(0,HEIGHT-1);
TEXT(0," (Press any key to continue)");
\(don't display this on the hardcopy)
CURL:= HEIGHT-1; CURH:= 78; \set cursor position for KEYIN
repeat until KEYIN;
CHOUT(0,FF);
end
else begin \DEV = 2, the printer
CRLF(DEV);
CRLF(DEV);
CRLF(DEV);
end;
TEXT(DEV," -- COMMAND-LINE COMMANDS --
DELETE SEARCH
D - Back a character S - For string (^^W = wild)
R - Rest of line N - Entire file (N text buffers)
E - Erase scoop
Z - Zap back to last form feed MISCELLANY
K - Kill entire text buffer / - List help summary on printer
L - List text buffer on printer
INSERT M - Margin (left, right) or (bell)
I - String Y - Center line
X - Scoop V - Copy text into command line
H - Hex value J - Re-execute command line (Jump)
P - Execute any command line (0-9)
FILES ESC - Command separator
G - Get next text buffer ESC ESC - Execute command line
A - Append from input file
W - Write to output file QUIT
O - Open input and output files Q - Quit and save text
C - Close output file T - Terminate and discard text
");
if DEV = 0 then
begin
CURSOR(0,HEIGHT-1);
TEXT(0," (Press any key to continue)");
\(don't display this on the hardcopy)
CURL:= HEIGHT-1; CURH:= 78; \set cursor position for KEYIN
repeat until KEYIN;
end
else begin
CLOSE(DEV);
end;
end; \HELP
\----------------------------------------------------------------------
proc SHOWRULER; \Display a ruler
\Inputs: LEFTCOL, RIGHTCOL, TICKMARKS
int I, AT, LM, RM, BL, IN;
begin
if KEYHIT then return;
CURSOR(0,HEIGHT-3); \output the ruler
\show the relative position in the file
AT:= WIDTH *CINX /( (BUFSIZ -(C2INX -CINX)) +1) + LEFTCOL;
LM:= PARAMS(LEFTMARGIN);
RM:= PARAMS(RIGHTMARGIN);
BL:= PARAMS(BELLCOL);
IN:= PARAMS(PARAINDENT) +LM;
for I:= LEFTCOL, RIGHTCOL-1 do
begin
case I of
AT: CHOUT(0,$7F); \%%%
BL: CHOUT(0,^^);
IN: CHOUT(0,^/);
LM,RM: CHOUT(0,^|)
other CHOUT(0,TICKMARKS(I));
end;
end; \SHOWRULER
\----------------------------------------------------------------------
proc SHOWCMDLINE; \Display the command line (DBUF, up to DINX)
\Inputs: DINX, DBUF, DN.
\Outputs: CURH, CURL.
reg int I, H;
begin
if KEYHIT then return;
H:=0;
CURSOR(0, HEIGHT-2);
for I:= 0, DINX(DN)-1 do
begin
if DBUF(DN,I) < $20 then
begin
CHOUT(0, ^^); \convert BEL to "^G", etc.
CHOUT(0, DBUF(DN,I)+$40);
H:= H +1;
end
else CHOUT(0, DBUF(DN,I));
H:= H +1;
end;
CURH:= H; CURL:= HEIGHT-2; \tell KEYIN where the cursor is
\ (kludge to help ENTERCMDLINE)
if KEYHIT then return;
while H<WIDTH do \blank rest of command line
begin
CHOUT(0,SP);
H:= H +1;
end;
end; \SHOWCMDLINE
\----------------------------------------------------------------------
proc SHOWSTATUS; \Display the status line at the bottom of the screen
\illegal? CMD: 0 SCOOP: 2000 S # s --> REM: 12345 AT: 12345 COL: 123
\WARNINGS: This routine assumes an 80-column screen.
\ If "CMD:" is moved then SELCMD should also be changed.
\Inputs: CINX, C2INX, CURH, DN, XINX, STATCOND.
reg int I, CH;
proc NUMOUT(NUM, SIZE);
\Display a left-justified number in a field represented by SIZE
\I.e: a 3-digit field is represented by SIZE = 100.
int NUM, SIZE;
begin
INTOUT(0,NUM);
if NUM=0 then NUM:=1;
while SIZE > NUM do
[CHOUT(0,SP);
NUM:= NUM *10];
end; \NUMOUT
begin \SHOWSTATUS
CURSOR(0,HEIGHT-1);
if KEYHIT then return;
loop for I:= 0, 8 do \show status message, make sure old
[CH:= STATCOND(I); \ message is erased, and don't flicker
if CH=0 ! I=8 then quit;
CHOUT(0, CH)];
for I:= I, 10 do CHOUT(0, SP);
TEXT(0,"CMD: ");
if KEYHIT then return;
NUMOUT(DN, 1000);
if KEYHIT then return;
TEXT(0,"SCOOP: ");
if KEYHIT then return;
NUMOUT(XBUFSIZ-XINX, 1000000);
if KEYHIT then return;
if WIDTH =40 then return;
TEXT(0,"S ");
CHOUT(0,if PARAMS(S1FLAG) then ^= else ^#);
if KEYHIT then return;
TEXT(0,if PARAMS(S2FLAG) then " s <-- " else " s --> ");
if KEYHIT then return;
TEXT(0,"REM: ");
if KEYHIT then return;
NUMOUT(C2INX -CINX, 10000000);
if KEYHIT then return;
TEXT(0,"AT: ");
if KEYHIT then return;
NUMOUT(CINX, 10000000);
if KEYHIT then return;
TEXT(0,"COL: ");
if KEYHIT then return;
NUMOUT(CURH, 100);
end; \SHOWSTATUS
\----------------------------------------------------------------------
proc DISPLAY; \Display the edit buffer for current cursor position
\Inputs: SHOWFLAG, CINX, C2INX, CURLINE
\Outputs: LEFTCOL, RIGHTCOL, CURH, CURL
int I, \scratch
CLINE, \index to the start of a line
L; \line counter
reg int C, \scratch index into text buffer
H; \horz. posn. from last carriage return (as displayed)
proc DISPCHAR; \Display an edit-buffer character
\Inputs: C, H, L; DEL ($7F) may not be displayed by the H/W
int CH;
proc DISPX(CH);
int CH;
begin
if H >=LEFTCOL & H<RIGHTCOL then \it is visible
CHOUT(0,CH);
H:= H+1; \bump horz. posn.
end; \DISPX
begin \DISPCHAR
CH:= BUFFER(C); \get char from buffer
C:= C+1;
if CH>=$21 then
begin \handle most characters
if H >=LEFTCOL & H<RIGHTCOL then \it is visible
CHOUT(0,CH); \DISPX inlined for speed
H:= H+1; \bump horz. posn.
end
else begin
if PARAMS(SHOWFLAG) then \show normally hidden CTRL chars
begin
if CH = SP then DISPX(SPIND)
else begin
DISPX(^^); \convert BEL into "^G", etc.
DISPX(CH+$40);
end;
end
else begin
if CH = SP then DISPX(SP)
else if CH = TAB then
repeat DISPX(SP) until (H & $0007) = 0;
end;
if CH = CR then \blank rest of the line
begin
while H < RIGHTCOL do \fill out line with spaces
begin
if H >=LEFTCOL then CHOUT(0,SP);
H:= H+1; \bump horz. posn.
end;
L:= L+1; \new line
H:= 0;
end;
end;
end; \DISPCHAR
begin \DISPLAY
\Find out how much horizontal scroll (LEFTCOL) is needed (this is complicated
\ because of tabs):
C:= CINX; \move C to the start of the line
while BUFFER(C-1)#CR & C>0 do C:= C-1;
CLINE:= C; \save the start of this line
\Move forward to the cursor and count the displayed characters (H) along the way:
H:= 0;
for I:= CLINE, CINX-1 do
begin
H:= H +1;
if BUFFER(I) < $20 then
if PARAMS(SHOWFLAG) then H:= H +1 \count the "^"
else if BUFFER(I) = TAB then
H:= (H + 7) & $FFF8 \move to next tab stop
else H:= H -1; \don't count hidden CTRL chars
end;
LEFTCOL:= H - WIDTH + 1; \(if H < WIDTH then LEFTCOL = 0)
if LEFTCOL < 0 then LEFTCOL:= 0;
RIGHTCOL:= WIDTH + LEFTCOL; \right-most displayed column + 1
if RIGHTCOL>COLMAX then
[RIGHTCOL:=COLMAX; LEFTCOL:= RIGHTCOL - WIDTH];
CURH:= H; CURL:=CURLINE; \tell KEYIN where the cursor is
if CURH = PARAMS(BELLCOL) then CHOUT(0,BEL);
\Display the line we are on (the cursor line) up to the cursor:
CURSOR(0,CURLINE);
H:= 0;
L:= CURLINE;
while C<CINX & not KEYHIT do DISPCHAR; \(beware of very long lines)
\Simply display the cursor as a block for now, and we'll fix it up later.
\ (We must do this because 38.4kb is very S-L-O-W...)
\First, make sure we're there (beware of fast typers).
CURSOR(if CURH<WIDTH then CURH else WIDTH-1, CURL);
C:= C2INX; \first, show the character (in case
if C<BUFSIZ then DISPCHAR \ it's a control character)
else H:= H +1; \leave room for the cursor block
\Move back and display a temporary block character:
CURSOR(if CURH<WIDTH then CURH else WIDTH-1, CURL);
CHOUT(0,$7F); \ %%%
\Resume displaying rest of line:
if H<WIDTH then CURSOR(H, L) else CURSOR(0, L+1);
\Display the rest of the text from the cursor down to the bottom of the screen:
while C<BUFSIZ & L<(HEIGHT-3) & not KEYHIT do DISPCHAR;
\If we're at the end of the buffer then fill out the rest of the display
\ with spaces:
while L<(HEIGHT-3) & not KEYHIT do
begin
if H >=LEFTCOL & H<RIGHTCOL then CHOUT(0,SP);
H:= H+1;
if H>=RIGHTCOL then [H:=LEFTCOL; L:=L+1];
end;
SHOWRULER; \(inputs LEFTCOL from DISPLAY)
SHOWSTATUS;
\Display lines from the line above the line the cursor is on up to the top
\ of the screen:
L:=CURLINE;
while CLINE>0 & L>0 & not KEYHIT do
begin
C:= CLINE; \move C to the start of the line
if C>0 then C:=C-1; \back over the CR
while BUFFER(C-1)#CR & C>0 do C:= C-1; \back up a line
CLINE:= C;
L:= L-1; \display the line
CURSOR(0,L);
H:= 0;
loop begin
if BUFFER(C)=CR ! KEYHIT then [DISPCHAR; quit];
DISPCHAR;
end;
L:= L-1; \undo next line from DISPCHAR
end;
\Fill out the top of the screen with blank lines if necessary:
while L>0 & not KEYHIT do
begin
L:= L-1;
CURSOR(0,L);
H:= 0;
while H < RIGHTCOL do
begin
if H >=LEFTCOL then CHOUT(0,SP);
H:= H+1;
end;
end;
\Replace the block with the character under the cursor:
C:= C2INX;
H:= CURH;
CURSOR(if CURH<WIDTH then CURH else WIDTH-1, CURL);
if C<BUFSIZ then DISPCHAR;
end; \DISPLAY
\----------------------------------------------------------------------
proc SETSTAT(STR, FLAG); \Set status condition
addr STR, FLAG; \STR may have 8 characters maximum
\Inputs: ERRFLAG.
\Outputs: STATCOND, ERRFLAG.
begin
if not ERRFLAG ! not FLAG then \don't set condition if we already have
begin \ an error -- only clear it
STATCOND:= STR;
ERRFLAG:= FLAG;
end;
end; \SETSTAT
\========================== BASIC COMMANDS ==============================\
proc SAVEPTRS; \Save edit-buffer pointers in case he screws up.
\Deleted characters reside in the gap and they may be restored simply by
\ restoring the edit pointers. These pointers are saved whenever a command,
\ such as a cursor move, messes up the gap.
begin
SCINX:= CINX;
SC2INX:= C2INX;
end; \SAVEPTRS
proc OOPS; \undo previous deletes (you can also undo this command)
int T;
begin
if CINX # SCINX ! C2INX#SC2INX then
begin
T:=CINX; CINX:=SCINX; SCINX:=T; \swap CINX and SCINX
T:=C2INX; C2INX:=SC2INX; SC2INX:=T; \swap C2INX and SC2INX
end
else SETSTAT("nothing?",true);
end; \OOPS
proc INSERT(CHAR); \Insert a char into the edit buffer
int CHAR;
begin
if CINX <C2INX then \if there's room...
begin
BUFFER(CINX):= CHAR;
CINX:= CINX+1;
\ if ACINX >= CINX then ACINX:= ACINX +1;
SAVEPTRS;
end
else SETSTAT("full?",true);
end; \INSERT
\----------------------------------------------------------------------
proc DELCHAR; \Delete back one char
begin
if CINX>0 then
begin
CINX:= CINX-1;
if XFLAG then \scoop-up buffer is on
begin
if XINX<XBUFSIZ then
begin
XBUF(XINX):= BUFFER(CINX);
XINX:= XINX+1;
end
else begin
SETSTAT("full?",true);
CINX:= CINX+1; \delete failed, undo it
end;
end
end
else SETSTAT("start?",true);
end; \DELCHAR
proc DELWORD; \Delete back one word
int CH;
begin
repeat DELCHAR; \delete all word separators
CH:=BUFFER(CINX);
until CH#CR & CH#SP & CH#TAB ! ERRFLAG;
loop begin \delete the word
CH:=BUFFER(CINX-1);
if CH=CR ! CH=SP ! CH=TAB ! ERRFLAG then quit;
DELCHAR;
if CINX = 0 then quit;
end;
end; \DELWORD
proc DELLINE; \Delete back one line
begin
repeat DELCHAR until BUFFER(CINX-1)=CR ! CINX=0 ! ERRFLAG;
end; \DELLINE (ERRFLAG? because XREG may be full)
proc DELALL; \Delete the entire edit buffer (kill)
begin \Notice that the scoop is not used here.
CINX:=0;
C2INX:=BUFSIZ;
end; \DELALL
proc ZAP; \Delete back to previous form feed or start
begin \ (the form feed is not deleted)
repeat DELCHAR until BUFFER(CINX-1)=FF ! CINX=0 ! ERRFLAG;
end; \ZAP
\----------------------------------------------------------------------
proc BACKCHAR; \Move back one char in buffer
begin
DELCHAR; \Move CINX back, checking for XREG, etc.
if not ERRFLAG then \if the delete succeeded then...
begin
C2INX:= C2INX-1;
BUFFER(C2INX):= BUFFER(CINX);
SAVEPTRS;
end;
end; \BACKCHAR
proc BACKWORD;
\Move back to the start of the current word or the previous word
int CH;
begin
repeat BACKCHAR; \back over all word separators
CH:=BUFFER(CINX);
until CH#CR & CH#SP & CH#TAB ! ERRFLAG;
loop begin
CH:=BUFFER(CINX-1);
if CH=CR ! CH=SP ! CH=TAB ! ERRFLAG then quit;
BACKCHAR;
if CINX = 0 then quit;
end;
end; \BACKWORD
proc BACKLINE;
\Move back to the start of the current line or the previous line
begin
repeat BACKCHAR until BUFFER(CINX-1)=CR ! CINX=0 ! ERRFLAG;
end; \BACKLINE
proc BACKPAGE; \Move backward one page
int I;
begin
if BUFFER(CINX-1) # CR then BACKLINE;
for I:=1,HEIGHT-3 do BACKLINE;
end; \BACKPAGE
proc BACKALL; \Move to the beginning of buffer
begin
if XFLAG then repeat BACKCHAR until CINX=0 ! ERRFLAG
else begin
BLIT(BUFFER, BUFFER +C2INX -CINX, CINX);
C2INX:= C2INX - CINX;
CINX:= 0;
end;
end; \BACKALL
\----------------------------------------------------------------------
proc FWDCHAR; \Move forward one char in buffer
begin
if C2INX<BUFSIZ then
begin
BUFFER(CINX):= BUFFER(C2INX);
CINX:= CINX+1; C2INX:= C2INX+1;
if XFLAG then
if XINX>0 then XINX:= XINX-1
else XFLAG:=false;
SAVEPTRS;
end
else SETSTAT("end?",true);
end; \FWDCHAR
proc FWDWORD; \Move to the start of the next word
\Note: This routine gives an error when moving to an EOF (not just beyond it)
int CH;
begin
repeat FWDCHAR; \Move forward to word separator
CH:=BUFFER(C2INX);
until CH=CR ! CH=SP ! CH=TAB ! ERRFLAG;
repeat FWDCHAR; \Move forward to non-word separator
CH:=BUFFER(C2INX);
until CH#CR & CH#SP & CH#TAB ! ERRFLAG;
end; \FWDWORD
proc FWDLINE; \Move to the start of the next line
begin
repeat FWDCHAR;
until BUFFER(CINX-1)=CR ! ERRFLAG;
end; \FWDLINE
proc FWDPAGE; \Move forward one page
int I;
begin
for I:=1,HEIGHT-3 do FWDLINE;
end; \FWDPAGE
proc FWDALL; \Move to the end of buffer
int I;
begin
if XFLAG then \If the X reg was on, it's gone now
[XINX:=0; XFLAG:=false];
BLIT(BUFFER +C2INX, BUFFER +CINX, BUFSIZ -C2INX);
CINX:= CINX + BUFSIZ - C2INX;
C2INX:= BUFSIZ;
SAVEPTRS;
end; \FWDALL
proc SWAPCURSORS; \Swap cursor with auxillary cursor
int I, T;
begin
if XFLAG then \If the X reg was on, it's gone now
[XINX:=0; XFLAG:=false];
\Move from current cursor position to auxillary cursor position:
if ACINX > CINX then \Move cursor forward
BLIT(BUFFER +C2INX, BUFFER +CINX, ACINX -CINX)
else \Move cursor backward
for I:= 1, CINX -ACINX do
BUFFER(C2INX-I):= BUFFER(CINX-I);
T:= ACINX; CINX:= ACINX; ACINX:= T; \swap primary and auxillary cursors
SAVEPTRS;
end; \SWAPCURSORS
\----------------------------------------------------------------------
proc DELREST; \Delete the rest of a line
begin
loop begin
if C2INX < BUFSIZ then C2INX:= C2INX +1
else [SETSTAT("end?", true); quit];
if BUFFER(C2INX-1) = CR then quit;
end;
end; \DELREST
proc FLIPCASE;
\Flip the case of the letter at the cursor and move forward
int CH;
begin
CH:=BUFFER(C2INX);
if C2INX<BUFSIZ & ((CH>=^A & CH<=^Z) ! (CH>=^a & CH<=^z)) then
begin
CH:= CH + (if CH >=^a then -$20 else $20);
BUFFER(C2INX):=CH;
FWDCHAR;
end
else begin
FWDCHAR;
SETSTAT("letter?",true);
end;
end; \FLIPCASE
proc LIST; \List edit buffer on printer
int C, CH;
begin
OPENO(PR);
FWDALL;
C:= 0;
while C < CINX do
begin
CH:= BUFFER(C);
C:= C+1;
if CH>=$21 then CHOUT(PR,CH) \Handle most characters
else begin
if PARAMS(SHOWFLAG) then \show normally hidden ctrl chars
begin
if CH = SP then CHOUT(PR,SPIND)
else begin
CHOUT(PR,^^); \convert BEL into "^G", etc.
CHOUT(PR,CH+$40);
end;
if CH = CR then CHOUT(PR,CH);
end
else CHOUT(PR,CH);
end;
end;
CRLF(PR); \do not close because of form feed
end; \LIST
\----------------------------------------------------------------------
proc XON; \Turn on scoop (X reg)
begin
XFLAG:= true;
SETSTAT("scoop",false); \(Show it right away)
end; \XON
proc XOFF; \Turn off scoop (X reg)
begin
XFLAG:= false;
SETSTAT("ok",false); \(Show it right away)
end; \XOFF
proc COPYX; \Copy scoop (X reg) into the edit buffer
\Note that the order of the text in XREG is backwards.
int X;
begin
XFLAG:=false; \Make sure it's off
X:= XINX;
while X >0 do
begin
X:= X-1;
INSERT(XBUF(X));
end;
end; \COPYX
\----------------------------------------------------------------------
func INHEX(D); \Insert literal hex value
int D;
int H;
func HEX(CH); \Return the hex value
int CH; \hex digit in ASCII
begin
case of
CH>=^0 & CH<=^9: return CH-$30;
CH>=^A & CH<=^F: return CH-$37;
CH>=^a & CH<=^f: return CH-$57
other SETSTAT("hex?",true);
end; \HEX
begin \INHEX
H:= HEX(DBUF(DN,D));
H:= H*$10 + HEX(DBUF(DN,D+1));
if not ERRFLAG then INSERT(H);
return D +2; \Return index to next command
end; \INHEX
func INSTRING(D); \Insert a string
int D; \Index into DBUF points to string
int CH;
begin
loop begin
CH:= DBUF(DN,D);
if CH = ESC then return D; \Return index to next command
INSERT(CH);
D:= D +1;
end;
end; \INSTRING
\----------------------------------------------------------------------
func SEARCH(D); \Forward search edit buffer for string.
int D; \Index of first string character on command line (DBUF)
\Returns index to next command (failed or not)
\Inputs: DBUF, DN, CINX, C2INX
int CH1, S1F;
reg int I, C;
func LOWER(CH); \Shift to lowercase if PARAMS(S1FLAG) is true
int CH;
begin
if S1F then
if CH>=^A & CH<=^Z then
return CH ! $20;
return CH;
end; \LOWER
proc FWDSEARCH; \Forward search edit buffer for string.
begin
C:= C2INX; \start searching from the cursor
I:= 0; \point to first char in string
loop begin
case SSTR(I) of
WILDCH, LOWER(BUFFER(C+I)):
begin \it matches
I:= I+1; \try next string character
if SSTR(I) = ESC then \the entire string matches
begin
C:= C +I; \point to end of string
if C > BUFSIZ then \(ignore garbage beyond buffer)
[SETSTAT("none?",true); quit];
\Move cursor forward to end of matching string:
BLIT(BUFFER +C2INX, BUFFER +CINX, C -C2INX);
CINX:= CINX + C -C2INX;
C2INX:=C;
SAVEPTRS;
quit;
end;
end
other begin \it doesn't match
C:= C +1; \move forward in edit buffer
if C >= BUFSIZ then \all done? then not found
[SETSTAT("none?",true); quit];
\Fast scan for first character (CH1):
\Wild characters are ignored
loop begin
if S1F then \if s = S then
for C:= C, BUFSIZ do
[if (BUFFER(C) ! $20) = CH1 then quit]
\(good candidate -- it's rechecked above)
else
for C:= C, BUFSIZ do
if BUFFER(C) = CH1 then quit;
quit; \quit if end of buffer
end;
I:= 0; \point to first char in string
end;
end; \LOOP
end; \FWDSEARCH
proc BACKSEARCH; \Backward search edit buffer for string.
begin
C:= CINX -I -1; \searching from the cursor - string length -1
I:= 0; \point to first char in string
loop begin
case SSTR(I) of
WILDCH, LOWER(BUFFER(C+I)):
begin \it matches
I:= I+1; \try next string character
if SSTR(I) = ESC then \the entire string matches
begin
if C < 0 then \(ignore garbage in front of buffer)
[SETSTAT("none?",true); quit];
C:= C +I; \point to end of string
\Move cursor backward to end of matching string:
BLIT(BUFFER+C, BUFFER+C2INX-(CINX-C), CINX-C);
C2INX:= C2INX -(CINX -C);
CINX:= CINX -(CINX -C);
SAVEPTRS;
quit;
end;
end
other begin \it doesn't match
C:= C -1; \move backward in edit buffer
if C < 0 then \all done? then not found
[SETSTAT("none?",true); quit];
\Fast scan for first character (CH1):
\Wild characters are ignored
\-C is a trick to fake: "for C:= C downto 0"
loop begin
if S1F then \if s = S then
for C:= -C, 0 do
[if (BUFFER(-C) ! $20) = CH1 then quit]
\(good candidate -- it's rechecked above)
else
for C:= -C, 0 do
if BUFFER(-C) = CH1 then quit;
quit; \quit if start of buffer
end;
C:= -C; \get positive C
I:= 0; \point to first char in string
end;
end; \LOOP
end; \BACKSEARCH
begin \SEARCH
S1F:= PARAMS(S1FLAG);
I:=0;
loop begin
SSTR(I):= LOWER(DBUF(DN,D)); \work with a copy of the string
if SSTR(I) = ESC then quit;
I:= I +1;
D:= D +1;
end;
CH1:= SSTR(0);
if CH1 = ESC then \Check for null string (no can handle)
[SETSTAT("null?",true); return D];
if S1F then CH1:= CH1 ! $20;
if PARAMS(S2FLAG) then BACKSEARCH else FWDSEARCH;
return D;
end; \SEARCH
\----------------------------------------------------------------------
proc INDENT; \Indent current line same as the preceding one
int COL, \The column number to indent to
C, \temporary index into text buffer
TABS, SPS, \number of tabs and spaces to insert
I; \scratch
begin
\Move to the beginning of the previous line:
if BUFFER(CINX-1) = CR then BACKLINE
else [BACKLINE; BACKLINE];
\Move the column counter according to the previous line's leading tabs
\ and spaces. (If the cursor was on the first line in the buffer, then
\ COL = 0)
COL:=0;
if not ERRFLAG then \it was not on the first line
begin \count the number of columns the
C:=C2INX; \ previous line is indented
loop begin
case BUFFER(C) of
SP: COL:= COL + 1;
TAB: [COL:= (COL + 8) & $FFF8] \move to next tab stop
other quit;
C:= C+1;
end;
\Move back to the beginning of the current line
FWDLINE;
end
else SETSTAT("ok",false);
\Delete all initial tabs and spaces on the current line:
loop begin
case BUFFER(C2INX) of
SP, TAB: if C2INX < BUFSIZ then [FWDCHAR; DELCHAR] else quit
other quit;
end;
\Insert tabs and spaces to move to the column determined above
TABS:= COL/8;
SPS:= REM(0);
for I:=1,TABS do INSERT(TAB);
for I:=1,SPS do INSERT(SP);
\(leave cursor at the first displayable character)
end; \INDENT
proc CENTER; \Center the current line between margins
int COL, \The column number to indent to
C, \temporary index into text buffer
TABS, SPS, \number of tabs and spaces to insert
I; \scratch
begin
\Move to the beginning of the line:
if BUFFER(CINX-1)#CR & CINX>0 then BACKLINE;
\Delete all initial tabs and spaces on the line:
loop begin
case BUFFER(C2INX) of
SP, TAB: if C2INX < BUFSIZ then [FWDCHAR; DELCHAR] else quit
other quit;
end;
\Count the number of printable characters remaining on the line:
C:= C2INX;
COL:= 0;
loop begin
if BUFFER(C)=CR ! C>=BUFSIZ then quit;
if BUFFER(C) >= SP & BUFFER(C) <= $7E then COL:= COL +1;
C:= C +1;
end;
\Calculate amount to indent line:
COL:= (PARAMS(RIGHTMARGIN) -PARAMS(LEFTMARGIN) -COL +1) /2;
\Insert tabs and spaces:
TABS:= COL/8;
SPS:= REM(0);
for I:=1,TABS do INSERT(TAB);
for I:=1,SPS do INSERT(SP);
\(leave cursor at the first displayable character)
end; \CENTER
\----------------------------------------------------------------------
func MARGIN(D); \Re-margin paragraph (or get bell column)
int D; \index to arguments (if any)
int LM, RM, \left & right margin columns
BELLFLAG, \this is a bell set command (not a margin)
COL, \column
I, \scratch
TABS, \number of tabs
SPS; \number of spaces
func NUMIN;
\Get positive integer from command line and return its value
\Also moves D to the char terminating the number
int NUM, CH;
begin
NUM:= 0;
CH:= DBUF(DN,D);
while CH = SP do \Eat leading spaces
begin
D:= D+1;
CH:= DBUF(DN,D);
end;
while CH>=^0 & CH<=^9 do
begin
NUM:= NUM *10 + (CH -^0);
if NUM < 0 then [SETSTAT("number?",true); return 0];
D:= D+1;
CH:= DBUF(DN,D);
end;
return NUM;
end; \NUMIN
begin \MARGIN
if DBUF(DN,D)>= ^0 & DBUF(DN,D)<= ^9 ! DBUF(DN,D)=^( then
begin \we have arguments -- go get 'em
if DBUF(DN,D)=^( then D:= D +1; \parentheses are optional
LM:= NUMIN; \get the new left margin column
BELLFLAG:= false; \assume it is not a bell setting
if DBUF(DN,D)=^, ! DBUF(DN,D)=SP then [D:= D +1; RM:= NUMIN]
else BELLFLAG:= true;
if DBUF(DN,D)=^, ! DBUF(DN,D)=SP then
[D:= D +1; PARAMS(PARAINDENT):= NUMIN];
if DBUF(DN,D)=^) then D:= D +1; \parentheses are optional
if BELLFLAG then \only one argument means set bell
[PARAMS(BELLCOL):= LM; return D+1]; \ and we're done
PARAMS(LEFTMARGIN):= LM; \set new left and right margin columns
PARAMS(RIGHTMARGIN):= RM;
end;
if ERRFLAG then return D;
if CINX>0 then BACKCHAR; \(margin back)
\Move to the end of the paragraph (2 CR's or end of buffer):
loop begin
if C2INX >= BUFSIZ then quit;
if BUFFER(C2INX) = CR then
begin
FWDCHAR;
if BUFFER(C2INX)=CR ! C2INX>=BUFSIZ then
[BACKCHAR; BACKCHAR; quit];
end;
FWDCHAR;
end;
\C2INX points to the last letter of the paragraph
SETSTAT("ok",false); \(in case there are 2 CR's at the beginning)
\Move to the start of the paragraph replacing CR's and tabs with spaces:
loop begin
if BUFFER(C2INX) = TAB then BUFFER(C2INX):= SP;
if BUFFER(C2INX) = CR then
begin
if CINX<=0 then [FWDCHAR; quit];
BACKCHAR;
if BUFFER(C2INX)=CR then [FWDCHAR; FWDCHAR; quit];
FWDCHAR;
BUFFER(C2INX):= SP;
end;
if CINX<=0 then quit;
BACKCHAR;
end;
SETSTAT("ok",false);
\Move to the end of the paragraph deleting multiple spaces:
while BUFFER(C2INX) = SP do \delete any spaces at the beginning
[FWDCHAR; DELCHAR];
loop begin
if BUFFER(C2INX) = SP then
begin
FWDCHAR;
while BUFFER(C2INX) = SP do
[FWDCHAR; DELCHAR];
end;
if BUFFER(C2INX)=CR ! C2INX>=BUFSIZ then quit;
FWDCHAR;
end;
SETSTAT("ok",false);
\Move to the start of the paragraph (now only one line long):
BACKLINE;
SETSTAT("ok",false);
COL:= PARAMS(LEFTMARGIN) +PARAMS(PARAINDENT); \the first line may be indented
loop begin
\insert tabs and spaces to get to the left margin:
TABS:= COL/8;
SPS:= REM(0);
for I:=1,TABS do INSERT(TAB);
for I:=1,SPS do INSERT(SP);
INSERT(CR); \insert a fake CR to mark our place
\(This is required if we have a word longer than a line and we are
\ are indenting with spaces.)
\Move to the right margin +1:
loop begin
if COL > PARAMS(RIGHTMARGIN) then quit;
FWDCHAR; \(sets ERRFLAG at end of buffer)
if BUFFER(C2INX) = CR ! ERRFLAG then \all done
begin
SETSTAT("ok",false); \in case of ERRFLAG
BACKLINE; \back up to fake CR
DELCHAR; \eat it
FWDLINE; \move to new line
FWDCHAR;
return D;
end;
if BUFFER(C2INX) >= $20 & BUFFER(C2INX) <= $7E then
COL:= COL +1; \don't count ctrl chars
end;
\Move back to previous space and replace it with a CR:
loop begin
if BUFFER(C2INX) = SP then
[BUFFER(C2INX):= CR; quit];
\Deal with case where a word is longer than a line:
if BUFFER(C2INX) = CR then \(our fake CR)
repeat begin
FWDCHAR;
if BUFFER(C2INX) = SP then
[BUFFER(C2INX):= CR; quit];
if BUFFER(C2INX) = CR ! ERRFLAG then quit;
end;
until false;
BACKCHAR;
if ERRFLAG then quit;
end;
if ERRFLAG then quit;
BACKLINE; \back up to fake CR
DELCHAR; \eat it
FWDLINE; \move to new line
COL:= PARAMS(LEFTMARGIN);
end;
return D;
end; \MARGIN
\============================ I/O COMMANDS ==============================\
\WARNING! One or both of the files may be missing ???
proc OPENFILES; \Open the files
begin
OPENI(DISK);
OPENO(DISK);
EOFFLAG:=false;
end; \OPENFILES
proc APPEND; \Append input file to edit buffer
\(XPL is fast; serial I/O is slow.)
reg int CH, LIMIT;
begin
LIMIT:= C2INX -PAD;
if EOFFLAG then
SETSTAT("eof?",true)
else loop begin
if CINX >= LIMIT then \if we're almost full, then start
begin \ looking for a carriage return
if CINX >= C2INX then \(test before we read)
[SETSTAT("full?",true); quit];
CH:= CHIN3;
if CH = EOF then
[EOFFLAG:= true; SETSTAT("eof",false); quit];
BUFFER(CINX):= CH;
CINX:= CINX+1;
if CH = CR then quit; \stop at the end of a line
end
else begin
CH:= CHIN3;
if CH = EOF then
[EOFFLAG:= true; SETSTAT("eof",false); quit];
BUFFER(CINX):= CH;
CINX:= CINX+1;
end;
end; \loop
SAVEPTRS;
end; \APPEND
proc WRITEBUF; \Write the edit buffer to the output disk file
reg int I;
begin
if not CLOSFLAG then
begin
FWDALL;
for I:= 0, CINX-1 do
CHOUT3(BUFFER(I));
end
else SETSTAT("closed?",true);
end; \WRITEBUF
proc NEXTBUF; \Get next buffer-full (ESC-G)
begin
WRITEBUF;
if not ERRFLAG then
begin
DELALL;
APPEND;
end;
end; \NEXTBUF
func BUFSEARCH(D); \Forward search N buffers for string
int D;
int DX, S2F;
begin
S2F:= PARAMS(S2FLAG); \Save current search direction
PARAMS(S2FLAG):= false; \Set to forward search
loop begin
DX:= SEARCH(D);
if ERRFLAG then \We didn't find it in this buffer
begin
if not EOFFLAG then
[SETSTAT("ok",false); \clear ERRFLAG from search
NEXTBUF;
SETSTAT("ok",false); \clear possible eof flag
BACKALL]
else quit; \(leaves last buffer in memory)
end
else quit; \found it, stop looking
end;
PARAMS(S2FLAG):= S2F; \Restore search direction
return DX; \return index to next command
end; \BUFSEARCH
proc QUIT; \Output the buffer and remaining input file to disk
reg int CH;
begin
if not CLOSFLAG then \save file to disk
begin
WRITEBUF;
if not EOFFLAG then \if we haven't encountered an EOF
begin \ shuffle the in file to the out file
loop begin
CH:= CHIN3;
if CH = EOF then quit;
CHOUT3(CH);
end;
EOFFLAG:= true; \(in case we don't exit)
end;
CLOSE(DISK);
CLOSFLAG:= true;
end;
CHOUT(0,FF);
exit;
end; \QUIT
\=========================== MACRO COMMANDS =============================\
proc CMD2TXT; \Copy command line to text buffer
int I;
begin
for I:= 0, DINX(DN)-1 do
INSERT(DBUF(DN,I));
end; \CMD2TXT
proc TXT2CMD; \Copy text into command line
int C, D;
begin
C:=C2INX;
D:=0;
loop begin
DBUF(DN,D):= BUFFER(C);
C:= C+1;
D:= D+1;
if D>=2 then if DBUF(DN,D-1)=ESC & DBUF(DN,D-2)=ESC then
[DINX(DN):= D; quit];
if C>=BUFSIZ ! D>=DBUFSIZ then
[SETSTAT("esc esc?",true);
quit];
end;
SHOWCMDLINE;
end; \TXT2CMD
proc SELCMD; \Select a command line [0-9]
int N;
begin
\Get the number of the command line.
\Move cursor to status line.
CURL:= HEIGHT -1; CURH:= 16;
N:= KEYIN;
if N>=^0 & N<=^9 then [DN:= N -^0; SHOWCMDLINE]
else SETSTAT("number?",true);
end; \SELCMD
\============================ GET COMMANDS ==============================\
proc BADCMD; \Handle unimplemented commands
SETSTAT("illegal?",true);
proc DOIMMCMD(CH); \Execute an immediate command (control character)
int CH; \ or insert the text character (CH)
begin
case CH of
CTRLA: FWDCHAR;
CTRLB: BACKWORD;
CTRLC: DELWORD;
CTRLD: FWDALL;
CTRLE: BACKALL;
CTRLF: XOFF;
CTRLG: SETSTAT("use J?",true); \(recursion may overflow stack)
CTRLH, DEL: DELCHAR;
\CTRLI is a TAB
CTRLJ: FWDPAGE;
CTRLK: BACKPAGE;
\CTRLL is a FF
\CTRLM is a CR
CTRLN: FWDWORD;
CTRLO: OOPS;
CTRLP: SELCMD;
CTRLQ: BACKCHAR;
CTRLR: XON;
CTRLS: FWDLINE;
CTRLT: PARAMS(SHOWFLAG):= not PARAMS(SHOWFLAG);
CTRLU: INDENT;
CTRLV: CMD2TXT;
CTRLW: BACKLINE;
CTRLX: DELLINE;
CTRLY: [COPYX; XINX:=0];
CTRLZ: FLIPCASE;
\CTRL@\$00: INSERT(SP); \(because of the damn Wyse terminal)
\CTRL[ IS AN ESC
\CTRL\ $1C: BADCMD; \SWAPCURSORS;
\CTRL]\$1D: PARAMS(S1FLAG):= not PARAMS(S1FLAG);
\CTRL^\$1E: INSERT(KEYIN); \insert next character literally
\CTRL_\$1F: PARAMS(S2FLAG):= not PARAMS(S2FLAG)
other INSERT(CHAR);
end; \DOIMMCMD
\----------------------------------------------------------------------
proc DOCMDLINE; \Execute a deferred command (from the command line)
int I, J, CH,
D, \index into command line buffer (DBUF)
DX, \index pointer to next command
COUNT; \repeat count
\Note that groups of commands may be repeated, each
\ group is separated by an ESC.
proc CALLCMD; \call a command line (recursive)
int CMD, SDN;
begin
CMD:= DBUF(DN,D+1) -^0; \get the command-line number
if CMD>=0 & CMD<=9 then
begin
SDN:= DN; \save current command line
DN:= CMD; \execute called command line
DOCMDLINE;
SETSTAT("ok", false); \don't stop now
DN:= SDN; \resume current command line
end
else SETSTAT("number?", true);
DX:= D +1; \skip the command-line number
end; \CALLCMD
begin \DOCMDLINE
D:= 0;
loop begin \loop over all chars in cmd line
if D >= DINX(DN) then quit;
CH:= DBUF(DN,D);
COUNT:= 0;
while CH>=^0 & CH<=^9 do \get repeat count
begin
COUNT:= COUNT *10 + (CH -^0);
if COUNT < 0 then [SETSTAT("number?",true); quit];
D:= D+1;
CH:= DBUF(DN,D);
end;
if COUNT <1 then COUNT:= 1; \do it at least once
if CH>=^a & CH<=^z then \convert to uppercase
CH:= CH-$20;
DX:= D +1; \assume a one-char command
\Execute the command COUNT number of times:
for I:= 1,COUNT do
begin
if (CH<$20 & CH#ESC) ! CH=$7F then DOIMMCMD(CH)
else
case CH of
^A: APPEND; \DEFERRED COMMANDS
^B: BADCMD; \DELLINE; (can insert CTRL-X)
^C: [CLOSE(DISK); CLOSFLAG:= true];
^D: DELCHAR; \(inserting DEL is awkward)
^E: XINX:= 0; \empty scoop
^F: BADCMD; \[FWDCHAR; if not ERRFLAG then DELCHAR];
^G: NEXTBUF; \read next text buffer
^H: DX:= INHEX(D+1); \insert literal hex
^I: DX:= INSTRING(D+1); \insert string
^J: DX:= 0; \restart command line
^K: DELALL; \kill entire buffer
^L: LIST; \list on printer
^M: DX:= MARGIN(D+1); \remargin
^N: DX:= BUFSEARCH(D+1); \search "N" buffers
^O: OPENFILES;
^P: CALLCMD; \call another command line
^Q: QUIT; \save file and return to Apex
^R: DELREST; \delete the rest of a line
^S: DX:= SEARCH(D+1); \search for string
^T: [CHOUT(0,FF); ABORT]; \terminate & save memory image
^U: BADCMD;
^V: [TXT2CMD; quit]; \text to command line
^W: WRITEBUF; \write edit buffer to disk
^X: COPYX; \copy scoop (X register)
^Y: CENTER;
^Z: ZAP; \delete back to form feed
^?: [HELP(0); SHOWCMDLINE]; \show help messages
^/: HELP(2); \print help messages
SP: []; \inert space (for readability)
ESC: [] \(command separator)
other BADCMD;
if ERRFLAG then quit;
end; \for loop
D:= DX; \point to next command in line buffer
end; \loop
end; \DOCMDLINE
\----------------------------------------------------------------------
proc ENTERCMDLINE; \Enter and execute a command line
int CH, SDINX;
begin
DBUF(DN,0):= ESC; \store and echo the escape key
DINX(DN):= 1;
SDINX:= 0;
\Display a temporary cursor in the body of the text:
CURSOR(if CURH<WIDTH then CURH else WIDTH-1, CURL);
CHOUT(0,$7F); \ %%%
SHOWCMDLINE; \show ESC and cleared command line
\this also sets the cursor position
repeat begin
CH:= KEYIN;
case CH of
DEL, CTRLH:
if DINX(DN) > 0 then DINX(DN):= DINX(DN) -1;
CTRLX: DINX(DN):= 0;
CTRLO: if SDINX = 0 then
begin \OOPS! Undelete command line
SDINX:= DINX(DN);
DINX(DN):= 0; \move forward until esc, esc
repeat DINX(DN):= DINX(DN) +1;
until (DBUF(DN,DINX(DN)-1) =ESC &
DBUF(DN,DINX(DN)) =ESC) ! DINX(DN) >=DBUFSIZ;
end
else begin \put things back (toggle CTRL-O)
DINX(DN):= SDINX;
SDINX:= 0;
end;
\CTRL^\$1E:
begin \Literal insert
CH:= KEYIN;
if DINX(DN) < DBUFSIZ then
[DBUF(DN,DINX(DN)):= CH; DINX(DN):= DINX(DN) +1]
else SETSTAT("length?",true); \(do not exit loop!)
end
other begin
if DINX(DN) < DBUFSIZ then
[DBUF(DN,DINX(DN)):= CH; DINX(DN):= DINX(DN) +1]
else SETSTAT("length?",true); \(do not exit loop!)
end;
SHOWCMDLINE;
end;
until (CH=ESC & DBUF(DN,DINX(DN)-2)=ESC) ! DINX(DN)=0; \ESC ESC or empty
DOCMDLINE;
end; \ENTERCMDLINE
\----------------------------------------------------------------------
proc INITIALIZE; \First-time (cold-start) initialization
int I,J;
addr STR;
begin
CINX:=0; \empty main buffer
C2INX:= BUFSIZ;
SAVEPTRS;
XINX:= 0; \empty X buffer (register)
XFLAG:= false;
EOFFLAG:= false;
SETSTAT("ok",false); \init status display and ERRFLAG
CURLINE:= (HEIGHT -6); \put cursor on 3rd line from bottom
CURH:=0; CURL:=CURLINE; \init cursor position
\Put starting message in command buffer and display it while we wait:
\ (Note that <ESC>- will not execute.)
STR:=" -- ED, Version 1.1 -- For help type: <ESC>?<ESC><ESC>";
for DN:=0,9 do \init empty (esc, esc is for OOPS)
begin
DINX(DN):= 0;
for I:=0,DBUFSIZ-1 do
DBUF(DN,I):= ESC;
end;
DN:= 0;
I:= 0;
repeat DBUF(DN,I):= STR(I);
I:= I +1;
until STR(I) = 0; \Note that the string will not execute
DINX(DN):= I;
CHOUT(0,FF);
SHOWCMDLINE;
\Set up ruler display:
for I:= 0,COLMAX do TICKMARKS(I):= ^-;
for I:= 5,COLMAX do [TICKMARKS(I):= ^+; I:= I+9];
J:= ^0;
for I:= 0,COLMAX do
[TICKMARKS(I):= J;
J:= J+1;
if J = ^: then J:=^A;
I:= I+9];
OPENFILES;
APPEND;
PARAMS(COLDFLAG):= false; \indicate we're initialized
end; \INITIALIZE
\----------------------------------------------------------------------
begin \MAIN
\The "+4 +4" trick prevents the RESERVE argument from changing the array
\ contents in case this is a restart.
XBUF:= RESERVE(XBUFSIZ +4) +4; \reserve all the arrays here
DINX:= RESERVE(10*4 +4) +4;
DBUF:= RESERVE(10*4 +4) +4;
for II:= 0,9 do DBUF(II):= RESERVE(DBUFSIZ*4 +4) +4;
TICKMARKS:= RESERVE(COLMAX+1 +4) +4;
SSTR:= RESERVE(DBUFSIZ +4) +4;
BUFSIZ:= FREE - 2000;
BUFSIZ:= BUFSIZ - REM(BUFSIZ/1000); \round down to even 1000
BUFFER:= RESERVE(BUFSIZ +4) +4;
ADDR:= 0; ADDR(CHKUSRF):= 0; \disable CTRL-C = abort, etc.
\ re-enabled by OPENI(0)
HEIGHT:= ADDR(CONHIGH);
WIDTH:= ADDR(CONWIDE);
CLOSFLAG:= false; \(ED can be restarted with a new output file)
PARAMS:= [true, 0, 72, 72, 0, false, false, false];
\[COLDFLAG, LEFTMARGIN, RIGHTMARGIN, BELLCOL, PARAINDENT, S1FLAG, S2FLAG, SHOWFLAG]
if PARAMS(COLDFLAG) then INITIALIZE \is this a restart?
else [CHOUT(0,FF); SHOWCMDLINE];
loop begin
DISPLAY; \display the text
CHAR:= KEYIN; \wait for key if not already struck
SETSTAT(if XFLAG then "scoop" else "ok",false); \init status display
if CHAR = ESC then ENTERCMDLINE \enter and execute a command line
else if CHAR = CTRLG then DOCMDLINE \(not allowed in deferred mode)
else DOIMMCMD(CHAR); \do immediate command or insert char
end;
end; \MAIN
hen DOCMDLINE \(not al